#pragma once
#include <cstring>
#include <vector>
#include <Eigen/Eigen>
#include <istream>

static const size_t INT32_SIZE = sizeof(int32_t);
static const size_t FLOAT_SIZE = sizeof(float);

#define READ_INT32(fp_, name_) std::int32_t name_; fp_.read((char*)(&name_), INT32_SIZE);
#define READ_SINGLE(fp_, name_) float name_; fp_.read((char*)(&name_), FLOAT_SIZE);

namespace XRwy {

	enum HairReaderMirrorType {
		MIRROR_NONE = 0,
		MIRROR_X = 1,
		MIRROR_Y = 2,
		MIRROR_XY = 3,
		MIRROR_Z = 4,
		MIRROR_XZ = 5,
		MIRROR_YZ= 6,
		MIRROR_XYZ = 7
	};

	class HairReader {
		using StrandStruct = std::vector<Eigen::Vector3f>;
		using StrandArray = std::vector<StrandStruct>;

	public:
		HairReader(const std::string file_path, float scale, HairReaderMirrorType mirror, int sample_freq);
		HairReader(const char *file_path, float scale, HairReaderMirrorType mirror, int sample_freq);
		HairReader(std::istream &input_stream, float scale, HairReaderMirrorType mirror, int sample_freq);

		HairReader(const HairReader && rhs) {
			strands = std::move(rhs.strands);
			particle_count = rhs.particle_count;
			strand_count = rhs.strand_count;
		}

		HairReader resample(const std::vector<size_t> &strand_ids) const;

		int get_particle_count() const;
		int get_strand_count() const;
		const StrandArray &get_strands() const;
	private:
		HairReader() {
			//used in private to construct a HairReader without anything but to fill the structure later
			strands = StrandArray();
			particle_count = 0;
			strand_count = 0;
		}

		StrandArray strands;
		int particle_count;
		int strand_count;

		void init(std::istream &input_stream, float scale, HairReaderMirrorType mirror, int sample_freq);
	};
}